package cn.cloud.all.security.oauth2.provider.token.store.jwk;

import cn.cloud.all.security.oauth2.common.exceptions.InvalidTokenException;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.sun.xml.internal.ws.api.pipe.Codecs;
import org.springframework.core.convert.converter.Converter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * A {@link Converter} that converts the supplied <code>String</code> representation of a JWT
 * to a <code>Map</code> of JWT Header Parameters.
 *
 * @author Joe Grandja
 * @author Vedran Pavic
 * @see <a target="_blank" href="https://tools.ietf.org/html/rfc7519">JSON Web Token (JWT)</a>
 */
class JwtHeaderConverter implements Converter<String, Map<String, String>> {
    private final JsonFactory factory = new JsonFactory();

    /**
     * Converts the supplied JSON Web Token to a <code>Map</code> of JWT Header Parameters.
     *
     * @param token the JSON Web Token
     * @return a <code>Map</code> of JWT Header Parameters
     * @throws InvalidTokenException if the JWT is invalid
     */
    @Override
    public Map<String, String> convert(String token) {
        Map<String, String> headers;

        int headerEndIndex = token.indexOf('.');
        if (headerEndIndex == -1) {
            throw new InvalidTokenException("Invalid JWT. Missing JOSE Header.");
        }

        byte[] decodedHeader;

        try {
            decodedHeader = Codecs.b64UrlDecode(token.substring(0, headerEndIndex));
        } catch (IllegalArgumentException ex) {
            throw new InvalidTokenException("Invalid JWT. Malformed JOSE Header.", ex);
        }

		try (JsonParser parser = this.factory.createParser(decodedHeader)) {
			headers = new HashMap<>();
			if (parser.nextToken() == JsonToken.START_OBJECT) {
				while (parser.nextToken() == JsonToken.FIELD_NAME) {
					String headerName = parser.getCurrentName();
					parser.nextToken();
					String headerValue = parser.getValueAsString();
					headers.put(headerName, headerValue);
				}
			}
		} catch (IOException ex) {
			throw new InvalidTokenException("An I/O error occurred while reading the JWT: " + ex.getMessage(), ex);
		}
		//
		return headers;
    }
}
